package cn.stalk.compare.field;

import cn.stalk.compare.DataAccessor;
import cn.stalk.compare.DataComparator;
import cn.stalk.compare.PrivateUtils;
import cn.stalk.compare.anno.AComparable;
import cn.stalk.compare.anno.AComparables;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 对象类数据比较器<br>
 * 比较的类支持注解@Comparable
 */
public class FieldComparator<T> extends DataComparator<T> {

    public FieldComparator(Class<T> type) {
        LinkedHashSet<DataAccessor<T, Object>> keyDataAccessors = new LinkedHashSet<>();
        Set<DataAccessor<T, Object>> dataAccessorList = new HashSet<>();
        FieldDataAccessor<T> accessor = null;
        
        AComparables comparables = type.getAnnotation(AComparables.class);
        if (null != comparables) {
            for (Field field : type.getDeclaredFields()) {
                accessor = new FieldDataAccessor<>(field);
                if (PrivateUtils.contains(comparables.value(), accessor.getName())) {
                    keyDataAccessors.add(accessor);
                    continue;
                }
                if (comparables.includes().length == 0 || PrivateUtils.contains(comparables.includes(), accessor.getName())) {
                    dataAccessorList.add(accessor);
                }
                if (comparables.excludes().length > 0 && PrivateUtils.contains(comparables.excludes(), accessor.getName())) {
                    dataAccessorList.remove(accessor);
                }
            }
        } else {
            for (Field field : type.getDeclaredFields()) {
                AComparable comparable = field.getAnnotation(AComparable.class);
                if (null == comparable) {
                    continue;
                }
                accessor = new FieldDataAccessor<>(field, comparable);
                if (comparable.value()) {
                    keyDataAccessors.add(accessor);
                } else {
                    dataAccessorList.add(accessor);
                }
            }
        }
        if (keyDataAccessors.isEmpty()) {
            throw new RuntimeException("Class " + type + " no primary key fileds.");
        }
        addKeyDataAccessors(keyDataAccessors);
        setDataAccessorList(dataAccessorList);
    }

}
